use std::path::Path;
use std::str;
+use serde::de::DeserializeSeed;
use serde_json;
use semver::Version;
use core::dependency::Dependency;
use core::{PackageId, SourceId, Summary};
-use sources::registry::{RegistryPackage, INDEX_LOCK};
+use sources::registry::{RegistryPackage, RegistryPackageDefault, INDEX_LOCK};
use sources::registry::RegistryData;
use util::{internal, CargoResult, Config, Filesystem};
///
/// The returned boolean is whether or not the summary has been yanked.
fn parse_registry_package(&mut self, line: &str) -> CargoResult<(Summary, bool)> {
+ let mut json_de = serde_json::Deserializer::from_str(line);
let RegistryPackage {
name,
vers,
features,
yanked,
links,
- } = super::DEFAULT_ID.with(|slot| {
- *slot.borrow_mut() = Some(self.source_id.clone());
- let res = serde_json::from_str::<RegistryPackage>(line);
- drop(slot.borrow_mut().take());
- res
- })?;
+ } = RegistryPackageDefault(&self.source_id).deserialize(&mut json_de)?;
let pkgid = PackageId::new(&name, &vers, &self.source_id)?;
let summary = Summary::new(pkgid, deps.inner, features, links)?;
let summary = summary.set_checksum(cksum.clone());
//! ```
use std::borrow::Cow;
-use std::cell::RefCell;
use std::collections::BTreeMap;
use std::fmt;
use std::fs::File;
pub api: Option<String>,
}
-#[derive(Deserialize)]
-struct RegistryPackage<'a> {
+pub struct RegistryPackage<'a> {
name: Cow<'a, str>,
vers: Version,
deps: DependencyList,
features: BTreeMap<String, Vec<String>>,
cksum: String,
yanked: Option<bool>,
- #[serde(default)]
links: Option<String>,
}
+pub struct RegistryPackageDefault<'a>(pub &'a SourceId);
+
+impl<'de, 'a> de::DeserializeSeed<'de> for RegistryPackageDefault<'a> {
+ type Value = RegistryPackage<'de>;
+
+ fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ deserializer.deserialize_map(self)
+ }
+}
+
+#[derive(Deserialize)]
+#[serde(field_identifier, rename_all = "lowercase")]
+enum Field {
+ Name,
+ Vers,
+ Deps,
+ Features,
+ Cksum,
+ Yanked,
+ Links,
+}
+
+impl<'a, 'de> de::Visitor<'de> for RegistryPackageDefault<'a> {
+ type Value = RegistryPackage<'de>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "struct RegistryPackage")
+ }
+
+ fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
+ where
+ A: de::MapAccess<'de>,
+ {
+ let mut name = None;
+ let mut vers = None;
+ let mut deps = None;
+ let mut features = None;
+ let mut cksum = None;
+ let mut yanked = None;
+ let mut links = None;
+ while let Some(key) = map.next_key()? {
+ match key {
+ Field::Name => {
+ if name.is_some() {
+ return Err(de::Error::duplicate_field("name"));
+ }
+ name = Some(map.next_value()?);
+ }
+ Field::Vers => {
+ if vers.is_some() {
+ return Err(de::Error::duplicate_field("vers"));
+ }
+ vers = Some(map.next_value()?);
+ }
+ Field::Deps => {
+ if deps.is_some() {
+ return Err(de::Error::duplicate_field("deps"));
+ }
+ deps = Some(map.next_value_seed(DependencyListDefault(self.0))?);
+ }
+ Field::Features => {
+ if features.is_some() {
+ return Err(de::Error::duplicate_field("features"));
+ }
+ features = Some(map.next_value()?);
+ }
+ Field::Cksum => {
+ if cksum.is_some() {
+ return Err(de::Error::duplicate_field("cksum"));
+ }
+ cksum = Some(map.next_value()?);
+ }
+ Field::Yanked => {
+ if yanked.is_some() {
+ return Err(de::Error::duplicate_field("yanked"));
+ }
+ yanked = Some(map.next_value()?);
+ }
+ Field::Links => {
+ if links.is_some() {
+ return Err(de::Error::duplicate_field("links"));
+ }
+ links = Some(map.next_value()?);
+ }
+ }
+ }
+ Ok(RegistryPackage {
+ name: name.ok_or_else(|| de::Error::missing_field("name"))?,
+ vers: vers.ok_or_else(|| de::Error::missing_field("vers"))?,
+ deps: deps.ok_or_else(|| de::Error::missing_field("deps"))?,
+ features: features.ok_or_else(|| de::Error::missing_field("features"))?,
+ cksum: cksum.ok_or_else(|| de::Error::missing_field("cksum"))?,
+ yanked: yanked.ok_or_else(|| de::Error::missing_field("yanked"))?,
+ links: links.unwrap_or(None),
+ })
+ }
+}
+
struct DependencyList {
inner: Vec<Dependency>,
}
}
}
-// TODO: this is pretty unfortunate, ideally we'd use `DeserializeSeed` which
-// is intended for "deserializing with context" but that means we couldn't
-// use `#[derive(Deserialize)]` on `RegistryPackage` unfortunately.
-//
-// I'm told, however, that https://github.com/serde-rs/serde/pull/909 will solve
-// all our problems here. Until that lands this thread local is just a
-// workaround in the meantime.
-//
-// If you're reading this and find this thread local funny, check to see if that
-// PR is merged. If it is then let's ditch this thread local!
-thread_local!(static DEFAULT_ID: RefCell<Option<SourceId>> = Default::default());
-
-impl<'de> de::Deserialize<'de> for DependencyList {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+struct DependencyListDefault<'a>(&'a SourceId);
+
+impl<'a, 'de> de::DeserializeSeed<'de> for DependencyListDefault<'a> {
+ type Value = DependencyList;
+ fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: de::Deserializer<'de>,
{
- return deserializer.deserialize_seq(Visitor);
-
- struct Visitor;
-
- impl<'de> de::Visitor<'de> for Visitor {
- type Value = DependencyList;
+ deserializer.deserialize_seq(self)
+ }
+}
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- write!(formatter, "a list of dependencies")
- }
+impl<'de, 'a> de::Visitor<'de> for DependencyListDefault<'a> {
+ type Value = DependencyList;
- fn visit_seq<A>(self, mut seq: A) -> Result<DependencyList, A::Error>
- where
- A: de::SeqAccess<'de>,
- {
- let mut ret = Vec::new();
- if let Some(size) = seq.size_hint() {
- ret.reserve(size);
- }
- while let Some(element) = seq.next_element::<RegistryDependency>()? {
- ret.push(parse_registry_dependency(element).map_err(|e| de::Error::custom(e))?);
- }
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "a list of dependencies")
+ }
- Ok(DependencyList { inner: ret })
- }
+ fn visit_seq<A>(self, mut seq: A) -> Result<DependencyList, A::Error>
+ where
+ A: de::SeqAccess<'de>,
+ {
+ let mut ret = Vec::new();
+ if let Some(size) = seq.size_hint() {
+ ret.reserve(size);
}
+ while let Some(element) = seq.next_element::<RegistryDependency>()? {
+ let dep = parse_registry_dependency(element, &self.0).map_err(de::Error::custom)?;
+ ret.push(dep);
+ }
+
+ Ok(DependencyList { inner: ret })
}
}
/// Converts an encoded dependency in the registry to a cargo dependency
-fn parse_registry_dependency(dep: RegistryDependency) -> CargoResult<Dependency> {
+fn parse_registry_dependency(
+ dep: RegistryDependency,
+ default: &SourceId,
+) -> CargoResult<Dependency> {
let RegistryDependency {
name,
req,
let id = if let Some(registry) = registry {
SourceId::for_registry(®istry.to_url()?)?
} else {
- DEFAULT_ID.with(|id| id.borrow().as_ref().unwrap().clone())
+ default.clone()
};
let mut dep = Dependency::parse_no_deprecated(&name, Some(&req), &id)?;